[READ-ONLY] Mirror of https://github.com/flo-bit/skywatched. review movies and tv shows, based on at proto
skywatched.app
7.3 kB
206 lines
1<script lang="ts">
2 import { type PageData } from './$types';
3 import { cn, nameToId } from '$lib/utils';
4
5 import Container from '$lib/Components/Layout/Container.svelte';
6 import Avatar from '$lib/Components/User/Avatar.svelte';
7 import { page } from '$app/stores';
8 import { watchedItems } from '$lib/state/user.svelte';
9 import { rateMovieModal } from '$lib/state/modals.svelte';
10
11 let { data }: { data: PageData } = $props();
12</script>
13
14<svelte:head>
15 <title>{data.result.title ?? data.result.name ?? ''} | skywatched</title>
16
17 <meta
18 name="description"
19 content={`Rate and review "${data.result.title ?? data.result.name ?? ''}" on skywatched`}
20 />
21
22 <meta property="og:url" content={$page.url.href} />
23 <meta property="og:type" content="website" />
24 <meta
25 property="og:title"
26 content="{data.result.title ?? data.result.name ?? ''} | skywatched.app"
27 />
28 <meta
29 property="og:description"
30 content={`Rate and review "${data.result.title ?? data.result.name ?? ''}" on skywatched`}
31 />
32 <meta property="og:image" content="{$page.url.href}/og.png" />
33
34 <meta name="twitter:card" content="summary_large_image" />
35 <meta property="twitter:domain" content="skywatched.app" />
36 <meta property="twitter:url" content={$page.url.href} />
37 <meta
38 name="twitter:title"
39 content="{data.result.title ?? data.result.name ?? ''} | skywatched.app"
40 />
41 <meta
42 name="twitter:description"
43 content={`Rate and review "${data.result.title ?? data.result.name ?? ''}" on skywatched`}
44 />
45 <meta name="twitter:image" content="{$page.url.href}/og.png" />
46</svelte:head>
47
48{#snippet buttons()}
49 {#if data.user && !watchedItems.hasRated(data.result)}
50 <button
51 class={cn(
52 'inline-flex items-center gap-2 rounded-md bg-white/10 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm transition-all duration-75 hover:bg-white/20 ',
53 watchedItems.hasRated(data.result)
54 ? 'bg-green-500/10 text-green-400 hover:bg-green-500/20'
55 : ''
56 )}
57 onclick={() => {
58 rateMovieModal.show({
59 movieId: data.result.movieId,
60 showId: data.result.showId,
61 kind: data.result.movieId ? 'movie' : 'tv',
62 name: data.result.original_title ?? data.result.original_name,
63 posterPath: data.result.poster_path,
64 currentRating: watchedItems.getRating(data.result)?.rating ?? 0,
65 currentReview: watchedItems.getRating(data.result)?.ratingText ?? ''
66 });
67 }}
68 >
69 rate {data.kind === 'movie' ? 'movie' : 'show'}
70 </button>
71 {/if}
72{/snippet}
73
74<div class="fixed inset-0 h-full w-full bg-black/50"></div>
75
76<Container class="relative z-10 pb-8 pt-4">
77 <div class="flex justify-center gap-4 px-4 pt-8">
78 <div class="flex-column">
79 {#if data.kind === 'cast'}
80 <div class="text-center text-sm font-medium">Cast1</div>
81 <Avatar
82 src={data.personDetails.profile_path
83 ? 'https://image.tmdb.org/t/p/w500' + data.personDetails.profile_path
84 : undefined}
85 size="size-44"
86 />
87 {:else}
88 <div class="text-center text-sm font-medium">Movie1</div>
89 <img
90 src="https://image.tmdb.org/t/p/w500{data.result.poster_path}"
91 alt=""
92 class="poster h-36 w-24 shrink-0 rounded-lg border border-white/10 sm:h-64 sm:w-44"
93 style:--name={`poster-${data.result.id}`}
94 />
95 {/if}
96 </div>
97 <div class="flex-column">
98 {#if data.kind2 === 'cast'}
99 <div class="text-center text-sm font-medium">Cast2</div>
100 <Avatar
101 src={data.person2Details.profile_path
102 ? 'https://image.tmdb.org/t/p/w500' + data.person2Details.profile_path
103 : undefined}
104 size="size-44"
105 />
106 {:else}
107 <div class="text-center text-sm font-medium">Movie2</div>
108 <img
109 src="https://image.tmdb.org/t/p/w500{data.result2.poster_path}"
110 alt=""
111 class="poster h-36 w-24 shrink-0 rounded-lg border border-white/10 sm:h-64 sm:w-44"
112 style:--name={`poster-${data.result2.id}`}
113 />
114 {/if}
115 </div>
116 </div>
117
118 <div class="px-4 pt-4 text-sm text-white">
119 <div class="mb-4 flex gap-2 sm:hidden">
120 {@render buttons()}
121 </div>
122 </div>
123
124 {#if data.cast.length > 0}
125 <div class="flex flex-col gap-x-6 px-4 pb-8 pt-4 text-sm text-white">
126 {#if data.kind === 'cast'}
127 <div class="text-center text-sm font-medium">Movies of {data.personDetails.name}</div>
128 <div class={cn('flex justify-start gap-x-6 overflow-x-auto')}>
129 {#each data.combinedCredits as castMember}
130 <a
131 href={`/game/movie/${castMember.id}-${castMember.title ?? castMember.name}/${data.kind2}/${data.ids2}-/${parseInt(data.couter) + 1}`}
132 class="flex flex-col items-center gap-1"
133 >
134 <img
135 src="https://image.tmdb.org/t/p/w342{castMember.poster_path}"
136 alt="movie poster for {castMember.title ?? castMember.name}"
137 class="poster size-32 w-32 object-cover object-center lg:size-full"
138 />
139 <div class="size-32 text-center text-sm font-medium">
140 {castMember.title ?? castMember.name}
141 </div>
142 </a>
143 {/each}
144 </div>
145 {:else}
146 <div class="text-center text-sm font-medium">cast of {data.result.title}</div>
147 <div class={'justify-left flex gap-x-6 overflow-x-auto'}>
148 {#each data.cast as castMember}
149 <a
150 href={`/game/cast/${castMember.id}-${nameToId(castMember.name)}/${data.kind2}/${data.ids2}-/${parseInt(data.couter) + 1}`}
151 class="flex flex-col items-center gap-1"
152 >
153 <Avatar
154 src={castMember.profile_path
155 ? 'https://image.tmdb.org/t/p/w500' + castMember.profile_path
156 : undefined}
157 size="size-32"
158 />
159 <div class="text-center text-xs font-medium">{castMember.name}</div>
160 <div class="text-center text-xs text-base-400">{castMember.character}</div>
161 </a>
162 {/each}
163 </div>
164 {/if}
165 {#if data.kind2 === 'cast'}
166 <div class="text-center text-sm font-medium">Movies of {data.person2Details.name}</div>
167 <div class={cn('flex gap-x-6 overflow-x-auto')}>
168 {#each data.combinedCredits2 as castMember}
169 <a
170 href={`/game/${data.kind}/${data.ids}-/movie/${castMember.id}-${castMember.title ?? castMember.name}/${parseInt(data.couter) + 1}`}
171 class="flex flex-col items-center gap-1"
172 >
173 <img
174 src="https://image.tmdb.org/t/p/w342{castMember.poster_path}"
175 alt="movie poster for {castMember.title ?? castMember.name}"
176 class="poster w-500 object-cover object-center lg:size-full"
177 />
178 <div class="size-32 text-center text-sm font-medium">
179 {castMember.title ?? castMember.name}
180 </div>
181 </a>
182 {/each}
183 </div>
184 {:else}
185 <div class="text-center text-sm font-medium">Cast of {data.result2.title}</div>
186 <div class={'justify-right flex gap-x-6 overflow-x-auto'}>
187 {#each data.cast2 as castMember}
188 <a
189 href={`/game/${data.kind}/${data.ids}-/cast/${castMember.id}-${castMember.title ?? castMember.name}/${parseInt(data.couter) + 1}`}
190 class="flex flex-col items-center gap-1"
191 >
192 <Avatar
193 src={castMember.profile_path
194 ? 'https://image.tmdb.org/t/p/w500' + castMember.profile_path
195 : undefined}
196 size="size-32"
197 />
198 <div class="text-center text-xs font-medium">{castMember.name}</div>
199 <div class="text-center text-xs text-base-400">{castMember.character}</div>
200 </a>
201 {/each}
202 </div>
203 {/if}
204 </div>
205 {/if}
206</Container>